﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TgcViewer.Example;
using AlumnoEjemplos.Ocio.Utils;
using AlumnoEjemplos.Ocio.Element;
using TgcViewer;
using TgcViewer.Utils.TgcGeometry;
using Ocio.Element;
using Microsoft.DirectX;
using System.Drawing;
using TgcViewer.Utils.Modifiers;

namespace AlumnoEjemplos.Ocio
{
    public class TestDeformacionPared : TgcExample
    {
       // private RepositorioObjetos repo = RepositorioObjetos.getInstance();
        private TgcPickingRay pickingRay = new TgcPickingRay();
        private Vector3 collisionPoint;
        private bool colisionDetectada = false;
        private Pared pared;

        //Agregados
        TgcBoundingSphere sphere;
        float radioDeImpacto;
        TgcArrow flechaDireccionImpacto;
        Vector3 anguloDisparo;

        public override string getCategory()
        {
            return "0_Ocio";
        }

        public override string getName()
        {
            return "Test-Deformaciion-Pared";

        }

        public override string getDescription()
        {
            return "";
        }

        public override void init()
        {
            this.initInterface();
            pared=new Pared(30, 30, 1);
        }

        public override void close()
        {
           
        }

        public override void render(float elapsedTime)
        {
            pared.render();
            TgcModifiers modifiers = GuiController.Instance.Modifiers;
            radioDeImpacto = (float)modifiers.getValue(ConstantsKey.RADIO_DE_IMPACTO);
            anguloDisparo = (Vector3)modifiers.getValue(ConstantsKey.ANGULO_DISPARO);
            if (GuiController.Instance.D3dInput.buttonPressed(TgcViewer.Utils.Input.TgcD3dInput.MouseButtons.BUTTON_LEFT))
            {
                this.detectarColision();

                if (colisionDetectada)
                {
                    //Seteo la esfera.
                    this.sphere.setValues(collisionPoint, radioDeImpacto);
                    this.sphere.render();
                    this.actualizarFlecha(this.flechaDireccionImpacto);
                    this.procesarDeformacion();
                }
            }
        }


        private void procesarDeformacion()
        {
            List<Ladrillo> objetosCandidatos = new List<Ladrillo>();

            foreach (Ladrillo obstaculo in pared.Ladrillos)
            {
                if (TgcCollisionUtils.testSphereAABB(this.sphere, obstaculo.BoundingBox))
                {
                    //objetosCandidatos.Add(obstaculo);
                    this.procesarDeformationPorLadrillo(obstaculo);
                }
            }

        }

        private void procesarDeformationPorLadrillo(Ladrillo ladrillo)
        {
 
           // VertexBuffer boxVertexBuffer = null;
            int listSize=ladrillo.toMesh("SelectedBox").getVertexPositions().Length;
            List<Vector3> verticesActualiados = new List<Vector3>();
            for (int i = 0; i< listSize;i++ )
            {
                Vector3 vertice = ladrillo.toMesh("SelectedBox").getVertexPositions()[i];
                float distancia=Vector3.Length(vertice - this.sphere.Center);
                if (distancia <= radioDeImpacto)
                {
                    //vertice.Z = vertice.Z + radioDeImpacto;
                    actualizarVertice(vertice, distancia, radioDeImpacto,this.flechaDireccionImpacto.PEnd);
                    Ladrillo coloredBox = Ladrillo.fromSize(vertice, new Vector3(1, 1, 1), Color.Blue);
                    coloredBox.render();
                }
               verticesActualiados.Add(vertice);

             }

              ladrillo.updateValues(verticesActualiados);
              ladrillo.BoundingBox = TgcBoundingBox.computeFromPoints(verticesActualiados.ToArray());
       }

        private void actualizarVertice(Vector3 vertice, float distancia, float radioDeImpacto,Vector3 direccionImpacto)
        {
            float desplazamiento = distancia/radioDeImpacto;
          //  vertice.X = vertice.X + ( desplazamiento*-1);
           // vertice.Y = vertice.Y + (desplazamiento * -1);
            vertice.Z = vertice.Z + (desplazamiento * -1);
          }

        //Inicializa los componentes de los laterales y elementos base.
        private void initInterface()
        {
            GuiController.Instance.Modifiers.addFloat(ConstantsKey.RADIO_DE_IMPACTO, 0f, 100f, 1f);
            GuiController.Instance.Modifiers.addVertex3f(ConstantsKey.ANGULO_DISPARO, new Vector3(-500f, -500f, -500f), new Vector3(500f, 500f, 500f), new Vector3(50f, 0f, 150f));

            //Se creara una espfera para identificar en base al radio que vertices estan dentro.
            sphere = new TgcBoundingSphere(new Vector3(0f, 0f, 0f), 0f);
            sphere.setRenderColor(Color.Red);

            //Creacion de la flcha que identifica el angulo de disparo
            flechaDireccionImpacto = new TgcArrow();
            //Cargar valores de la flecha
            flechaDireccionImpacto.PStart = new Vector3(0, 0, 0); ;
            flechaDireccionImpacto.PEnd = new Vector3(0, 0, 0); ;
            flechaDireccionImpacto.Thickness = 0.1f;
            flechaDireccionImpacto.HeadSize = new Vector2(0.2f,0.2f);
            flechaDireccionImpacto.BodyColor = Color.Pink;
            flechaDireccionImpacto.HeadColor = Color.Green;


        }


                //Ejecuta la logica colision con el Ladrillo..
        private void detectarColision()
        {
            //Si hacen clic con el mouse, ver si hay colision RayAABB
            if (GuiController.Instance.D3dInput.buttonPressed(TgcViewer.Utils.Input.TgcD3dInput.MouseButtons.BUTTON_LEFT))
            {
                //Actualizar Ray de colisión en base a posición del mouse
                pickingRay.updateRay();
                //Testear Ray contra el AABB de todos los meshes
                foreach (Ladrillo box in pared.Ladrillos)
                {
                    TgcBoundingBox aabb = null;
                    aabb = box.BoundingBox;
                    //Ejecutar test, si devuelve true se carga el punto de colision collisionPoint
                    if (colisionDetectada = TgcCollisionUtils.intersectRayAABB(pickingRay.Ray, aabb, out collisionPoint))
                    {
                        break;
                    }
                }
            }
        }

        //Actualiza el estado de la flecha en base a las variaciones de panel.
        private void actualizarFlecha(TgcArrow flechaDireccionImpacto)
        {
            this.flechaDireccionImpacto.PStart = anguloDisparo;
            this.flechaDireccionImpacto.PEnd = collisionPoint;
            this.flechaDireccionImpacto.BodyColor = Color.Pink;
            this.flechaDireccionImpacto.HeadColor = Color.Green;
            //Actualizar valores para hacerlos efectivos
            this.flechaDireccionImpacto.updateValues();
            this.flechaDireccionImpacto.render();
        }
    }
}
